home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / WAIS / ir / irhash.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-02  |  22.6 KB  |  714 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE:
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.
  4.  
  5.    Brewster@think.com
  6. */
  7.  
  8. /* The memory hashtables for building an index. */
  9. /* -brewster 5/90 */
  10.  
  11. /* main functions:
  12.  *   add_word
  13.  *   finished_add_word
  14.  *   look_up_word
  15.  *
  16.  * The idea is to store up a bunch of words before going to disk.
  17.  * A word entry points to where it will go on disk, and
  18.  * accumulates the entries before doing it.
  19.  *
  20.  * Some of the policy issues in this file are:
  21.  *   How much weight should the first occurance of a word in a document get
  22.  *   over the other occurances.  The first occurance should be worth more
  23.  *   so that words with 3 occurances of "dog" and not "cat"'s should not 
  24.  *   win out over 1 "dog" and 1 "cat" if the question is "Tell me about cats
  25.  *   torture dogs"
  26.  *   The extra weight is 5 at this point.
  27.  *
  28.  */
  29.  
  30. /* To Do:
  31.  *  Improve the hashing functions.
  32.  *  done: stop inserting into hash table after max number have been accumulated
  33.  *  done: make flush not flush buffers that are too big.
  34.  */
  35.  
  36. #include <ctype.h>
  37. #include <string.h>     /* for strlen(), memset() */
  38.  
  39. #include "panic.h"
  40. #include "cutil.h"
  41. #include "irfiles.h"
  42. #include "irhash.h"
  43. #include "stoplist.h"
  44. #include "irinv.h"
  45.  
  46. #ifdef UNIX
  47. #define PRINT_AS_INDEXING true /* also defined in irtfiles.c and irfiles.c */
  48. #else 
  49. #define PRINT_AS_INDEXING false
  50. #endif
  51.  
  52.  
  53. /*===========================*
  54.  *===  Hashing Functions  ===*
  55.  *===========================*/
  56.  
  57. /* #define FAST_HASH */
  58.  
  59. #ifdef FAST_HASH
  60.  
  61. /* courtesy ses@ccgr.technion.ac.il, but it turns out in
  62.    informal timings that it increases the index time.  sigh. */
  63.  
  64. static char coeff[] = {
  65.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  66.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  67.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  68.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  69.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  70.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  71.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1,
  72.         61,59,53,47,43,41,37,31,29,23,17,13,11,7,3,1};
  73.  
  74. long hash_word(wd,below_n)
  75. char *wd;
  76. long below_n;
  77. {
  78.   register char *foo;
  79.   register long hash = 0;
  80.   register int l;
  81.  
  82.   for(l=0,foo=wd;l<sizeof(coeff) && *foo ;l++)
  83.     hash = hash + (*(foo++) * coeff[l]);
  84.  
  85.   return (hash % below_n);
  86. }
  87. #endif /* def FAST_HASH*/
  88.  
  89. #ifndef FAST_HASH
  90.  
  91. /* these stink -brewster */
  92.  
  93. static long random_array_3[256] = 
  94. {142L, 176L, 108L, 210L, 109L, 223L, 214L, 251L, 
  95.    102L, 86L, 91L, 9L, 247L, 139L, 115L, 71L, 
  96.    63L, 35L, 126L, 77L, 209L, 175L, 120L, 28L, 
  97.    44L, 198L, 21L, 125L, 245L, 250L, 10L, 119L, 
  98.    127L, 60L, 81L, 226L, 216L, 182L, 172L, 72L, 
  99.    151L, 178L, 116L, 224L, 244L, 41L, 212L, 73L, 
  100.    190L, 248L, 173L, 18L, 82L, 27L, 97L, 26L, 
  101.    79L, 169L, 74L, 170L, 83L, 189L, 101L, 141L, 
  102.    230L, 55L, 135L, 220L, 187L, 201L, 95L, 39L, 
  103.    186L, 131L, 105L, 36L, 255L, 203L, 155L, 84L, 
  104.    160L, 75L, 254L, 235L, 51L, 243L, 158L, 14L, 
  105.    148L, 167L, 149L, 96L, 68L, 161L, 45L, 233L, 
  106.    11L, 19L, 3L, 38L, 195L, 48L, 144L, 15L, 
  107.    171L, 94L, 180L, 29L, 252L, 181L, 80L, 4L, 
  108.    20L, 213L, 23L, 143L, 7L, 236L, 76L, 110L, 
  109.    22L, 58L, 17L, 253L, 66L, 246L, 40L, 112L, 
  110.    179L, 130L, 87L, 124L, 240L, 193L, 107L, 165L, 
  111.    202L, 31L, 106L, 43L, 93L, 99L, 147L, 199L, 
  112.    129L, 197L, 32L, 229L, 150L, 46L, 157L, 128L, 
  113.    136L, 153L, 121L, 113L, 237L, 194L, 218L, 104L, 
  114.    78L, 184L, 62L, 159L, 227L, 222L, 47L, 53L, 
  115.    1L, 24L, 118L, 177L, 49L, 185L, 98L, 90L, 
  116.    34L, 192L, 200L, 221L, 232L, 146L, 114L, 137L, 
  117.    67L, 225L, 154L, 241L, 50L, 56L, 145L, 5L, 
  118.    188L, 207L, 231L, 228L, 6L, 183L, 219L, 217L, 
  119.    156L, 30L, 174L, 205L, 103L, 37L, 133L, 152L, 
  120.    117L, 196L, 164L, 249L, 239L, 64L, 242L, 59L, 
  121.    168L, 2L, 162L, 13L, 92L, 85L, 70L, 0L, 
  122.    52L, 65L, 166L, 163L, 215L, 69L, 140L, 25L, 
  123.    33L, 100L, 42L, 54L, 88L, 206L, 122L, 57L, 
  124.    16L, 208L, 134L, 132L, 138L, 89L, 8L, 234L, 
  125.    12L, 238L, 111L, 204L, 61L, 211L, 191L, 123L};
  126.  
  127.  
  128. static long random_array_2[256] = 
  129. {818L, 789L, 854L, 862L, 704L, 1019L, 390L, 887L, 
  130.    93L, 204L, 269L, 59L, 743L, 219L, 191L, 769L, 
  131.    911L, 435L, 805L, 448L, 142L, 1000L, 149L, 264L, 
  132.    639L, 504L, 699L, 934L, 266L, 661L, 318L, 211L, 
  133.    117L, 549L, 90L, 536L, 378L, 944L, 400L, 599L, 
  134.    592L, 883L, 985L, 606L, 759L, 456L, 581L, 119L, 
  135.    106L, 310L, 412L, 931L, 233L, 561L, 973L, 870L, 
  136.    377L, 349L, 334L, 354L, 249L, 585L, 799L, 899L, 
  137.    545L, 553L, 848L, 625L, 438L, 890L, 791L, 1014L, 
  138.    337L, 374L, 489L, 146L, 123L, 907L, 977L, 22L, 
  139.    396L, 241L, 198L, 424L, 136L, 715L, 867L, 684L, 
  140.    560L, 244L, 293L, 1017L, 397L, 778L, 725L, 78L, 
  141.    184L, 656L, 389L, 635L, 982L, 158L, 203L, 878L, 
  142.    323L, 394L, 73L, 18L, 837L, 996L, 58L, 62L, 
  143.    161L, 451L, 534L, 746L, 485L, 222L, 25L, 666L, 
  144.    28L, 21L, 420L, 147L, 522L, 74L, 474L, 362L, 
  145.    253L, 172L, 195L, 622L, 559L, 790L, 288L, 455L, 
  146.    263L, 538L, 355L, 417L, 810L, 576L, 685L, 797L, 
  147.    641L, 315L, 347L, 786L, 487L, 966L, 579L, 181L, 
  148.    499L, 429L, 688L, 140L, 278L, 719L, 186L, 872L, 
  149.    997L, 319L, 173L, 882L, 1008L, 573L, 431L, 830L, 
  150.    774L, 654L, 235L, 121L, 925L, 529L, 593L, 92L, 
  151.    954L, 434L, 213L, 79L, 284L, 510L, 763L, 655L, 
  152.    300L, 447L, 4L, 461L, 506L, 88L, 99L, 459L, 
  153.    220L, 780L, 523L, 178L, 303L, 578L, 287L, 827L, 
  154.    419L, 521L, 114L, 703L, 664L, 892L, 304L, 876L, 
  155.    352L, 331L, 35L, 896L, 341L, 450L, 812L, 350L, 
  156.    316L, 705L, 815L, 935L, 15L, 572L, 503L, 467L, 
  157.    306L, 976L, 118L, 760L, 807L, 809L, 339L, 442L, 
  158.    758L, 546L, 327L, 527L, 537L, 383L, 82L, 531L, 
  159.    728L, 428L, 768L, 675L, 814L, 919L, 133L, 682L, 
  160.    906L, 163L, 716L, 692L, 174L, 464L, 708L, 922L};
  161.  
  162.  
  163. /*  
  164. static long random_char_code _AP((long ch,long offset));
  165. static long random_char_code(ch,offset)
  166. long ch;
  167. long offset;
  168. {
  169.  
  170.     return(random_array_3[ (offset + (ch & 0xFF)) % 256]);
  171. }
  172. */
  173.  
  174. #define random_char_code(ch,offset)\
  175.        (random_array_3[ (offset + (ch ) ) & 0xff])
  176.  
  177. /* assumes the word has been downcased already */
  178.  
  179. static long hash_word(wd,below_n)
  180. char *wd;
  181. long below_n;
  182. {
  183.          
  184.         register long i=0;
  185.         register long answer = 0;
  186.     register char* foo;
  187.  
  188.     foo=wd;
  189.         for (i = 0; *foo; foo++,i++) {
  190.         answer = answer ^ (random_array_2[i % 256] +
  191.                    ((0 == (i & 1)) ? 
  192.                     random_char_code((long)*foo, i)
  193.                     : (random_char_code((long)*foo, i))
  194.                     << 8));            
  195.           }
  196.         return(answer % below_n);
  197. }
  198.  
  199. #endif /* ndef FAST_HASH */
  200.  
  201. static long hash_word_2 _AP((char *wd));
  202. static long hash_word_2(wd)
  203. char *wd;
  204. {
  205.   long hash = hash_word(wd, ((1L << (8 * DICTIONARY_ENTRY_HASH_CODE_SIZE))
  206.                  - 2));
  207.   return(1 + hash);
  208.                               
  209. }
  210.  
  211.  
  212. /* ================================
  213.    ===  Word Occurance Buffers  ===
  214.    ================================ */
  215.  
  216. /* Word occurance buffers
  217.  * This is a simple memory allocator for use with the word memory hashtable.
  218.  * Since the buffers are tiny, this is done as a copy-sweep GC scheme.
  219.  * Oh, I long for the storage system of lisp.
  220.  */
  221. char *first_word_occurance_buffer = NULL;  /* allocate blocks out of this */
  222. char *last_word_occurance_buffer = NULL;
  223. long word_occurance_block_length = 256000;  /* maybe this should be larger? */
  224. char * word_occurance_free_ptr = NULL;
  225.  
  226. char *make_word_occurrance_block(size)
  227. long size;
  228.  
  229. {
  230.   /* allocates a word_occurance_block out of the buffers */
  231.   /* old way: s_malloc((size_t)size); */
  232.   /* returns a pointer to a piece of memory */
  233.   if(NULL == first_word_occurance_buffer){
  234.     /* initialize it */
  235.     first_word_occurance_buffer = 
  236.       (char *)s_malloc(MAX(word_occurance_block_length,
  237.                sizeof(size_t)+ size));
  238.     *(char **)first_word_occurance_buffer = NULL; /* set the end */
  239.     last_word_occurance_buffer = first_word_occurance_buffer;
  240.     word_occurance_free_ptr = first_word_occurance_buffer + sizeof(size_t);
  241.   }
  242.   if((long)word_occurance_free_ptr + size >= 
  243.      word_occurance_block_length + (long)last_word_occurance_buffer){
  244.     /* then allocate a new block */
  245.     char * new_block = (char *)s_malloc(MAX(word_occurance_block_length,
  246.                         sizeof(size_t)+ size));
  247.     *(char **)new_block = NULL; /* set the end of the chain */
  248.     *(char **)last_word_occurance_buffer = new_block;
  249.     word_occurance_free_ptr = new_block + sizeof(size_t);
  250.     last_word_occurance_buffer = new_block;
  251.   }
  252.   /* allocate away */    
  253.   { char * answer = word_occurance_free_ptr;
  254.     word_occurance_free_ptr += size;    
  255.     return(answer);  
  256.   }
  257. }
  258.  
  259. void free_word_occurance_block(block)
  260. char *block;
  261. {
  262.   /* this is not used with the new scheme, but is here in case
  263.      malloc is a win on some systems */
  264.   /* old way s_free(block); */
  265. }
  266.  
  267. static void flush_word_occur_bufs_internal
  268.   _AP((char* head_of_list));
  269.  
  270. static void flush_word_occur_bufs_internal(head_of_list)
  271. char* head_of_list;
  272. /* frees all word occurance buffers.  This should be done with care */
  273. {      
  274.   while(1){
  275.     char * next_block;
  276.     if(NULL == head_of_list)
  277.       break;
  278.     next_block = *(char **)head_of_list;
  279.     s_free(head_of_list);
  280.     head_of_list = next_block;
  281.   }
  282. }
  283.  
  284. void flush_word_occurance_buffers()
  285. {
  286.   /* frees all word occurance buffers.  This should be done with care */
  287.   flush_word_occur_bufs_internal(first_word_occurance_buffer);
  288.   first_word_occurance_buffer = NULL;
  289.   word_occurance_free_ptr = NULL;
  290.   last_word_occurance_buffer = NULL;
  291. }
  292.  
  293.  
  294. void gc_word_occurance_buffers(the_word_memory_hashtable)
  295. word_memory_hashtable * the_word_memory_hashtable;
  296.  
  297. {
  298.   /* go through the word_memory_hashtable and copy what we need into another 
  299.      list of buffers, the flush the old ones */
  300.   /* not needed yet */
  301. }
  302.  
  303.  
  304.  
  305. /* ===============================
  306.    ===  Word Memory Hashtable  ===
  307.    =============================== */
  308.  
  309. static long find_location _AP((char* word,word_memory_hashtable* 
  310.                    the_word_memory_hashtable));
  311.  
  312. static long 
  313. find_location(word,the_word_memory_hashtable)
  314. char* word;
  315. word_memory_hashtable* the_word_memory_hashtable;
  316. /* returns the location that the word should go (or is).  returns -1 if 
  317.  * the hashtable is full and the word is not there
  318.  */
  319. {
  320.   long hash_code = hash_word(word, the_word_memory_hashtable->size);
  321.   long i;
  322.   long hash_code_2 = hash_word_2(word);
  323.  
  324.   for(i = hash_code; i < (hash_code + the_word_memory_hashtable->size); 
  325.       i++){
  326.     long index = i % the_word_memory_hashtable->size; 
  327.     if(NULL == the_word_memory_hashtable->contents[index]){
  328.       /* found an open spot, return it */
  329.       return(index);
  330.     }
  331.     else 
  332.       if(hash_code_2 == the_word_memory_hashtable->contents[index]->hash_code
  333.      &&
  334.      strcmp(word, the_word_memory_hashtable->contents[index]->word) == 0){
  335.     /* we win, return it */
  336.     return(index);
  337.       }
  338.     /* keep looking */
  339.   }
  340.   return(-1);
  341. }
  342.  
  343. /* this pushes all word entries to the top of the word_memory_hashtable
  344.  * therefore messing up the hashing order, but allows for quick sorting
  345.  * just before dumping to disk.
  346.  */
  347. void collapse_word_memory_hashtable(the_word_memory_hashtable)
  348. word_memory_hashtable *the_word_memory_hashtable;
  349. {
  350.   long insert_index = 0;
  351.   long extract_index;
  352.   for(extract_index = 0; extract_index < the_word_memory_hashtable->size;
  353.       extract_index++){
  354.     word_entry *entry = the_word_memory_hashtable->contents[extract_index];
  355.     if(NULL != entry)
  356.       the_word_memory_hashtable->contents[insert_index++] = entry;
  357.   }
  358. }
  359.  
  360. static int word_entry_compare _AP((word_entry**i,word_entry** j));
  361.  
  362. static int word_entry_compare(i,j)
  363. word_entry **i;
  364. word_entry **j;
  365. {
  366.   return(strcmp((*i)->word, (*j)->word));
  367. }
  368.  
  369. /* assumes that the word_memory_hashtable has been compressed */
  370. void sort_word_memory_hashtable(the_word_memory_hashtable)
  371. word_memory_hashtable *the_word_memory_hashtable;
  372. {
  373.   qsort(the_word_memory_hashtable->contents,
  374.     the_word_memory_hashtable->number_of_entries,
  375.     (size_t)sizeof(char *),
  376.     word_entry_compare);
  377. }
  378.  
  379.       
  380. /* for     debugging */
  381. void print_word_memory_hashtable(the_word_memory_hashtable)
  382. word_memory_hashtable* the_word_memory_hashtable;
  383. {
  384.   if (NULL == the_word_memory_hashtable){
  385.     cprintf(PRINT_AS_INDEXING, "No Hashtable allocated\n");
  386.     return;
  387.   }
  388.   cprintf(PRINT_AS_INDEXING, "Number of entries possible: %ld\n", 
  389.       the_word_memory_hashtable->size);
  390.   cprintf(PRINT_AS_INDEXING, "Number of entries allocated: %ld\n",
  391.       the_word_memory_hashtable->number_of_entries);
  392.   if(NULL != the_word_memory_hashtable->contents){
  393.     long i;
  394.     /* print the entries */
  395.     printf("The entries are:\n");
  396.     for(i = 0; i < the_word_memory_hashtable->size; i++){
  397.       if(NULL != the_word_memory_hashtable->contents[i]){
  398.     printf(" Position: %ld word: \"%s\" %ld occurances\n", i, 
  399.            the_word_memory_hashtable->contents[i]->word,
  400.            the_word_memory_hashtable->contents[i]->number_of_occurances);    
  401.       }
  402.     }
  403.   }
  404. }
  405.  
  406. static word_entry* look_up_word _AP((char* word,word_memory_hashtable*
  407.                      the_word_memory_hashtable));
  408.   
  409. static word_entry* 
  410. look_up_word(word,the_word_memory_hashtable)
  411. char* word;
  412. word_memory_hashtable* the_word_memory_hashtable;
  413. {
  414.   /* looks up the word in the dictionary and returns
  415.    * a pointer to the word_entry.
  416.    * If is not present, then it mallocs a new word entry.
  417.    */
  418.   /* this is a pretty dumb hashing scheme XXX */
  419.   long index = find_location(word, the_word_memory_hashtable);
  420.   if(-1 == index){
  421.     panic("the hashtable is completely full.  It should have been grown\n");
  422.   }
  423.   if(NULL == the_word_memory_hashtable->contents[index]){
  424.     /* make a new entry */
  425.     word_entry *new_entry = 
  426.       &the_word_memory_hashtable->word_entry_block
  427.     [the_word_memory_hashtable->number_of_entries++];
  428.  
  429.     if(NULL == new_entry){
  430.       panic("malloc failed for word_entry\n"); 
  431.     }
  432.     strncpy(new_entry->word, word, MAX_WORD_LENGTH);
  433.     new_entry->hash_code = hash_word_2(word);      
  434.     new_entry->number_of_occurances = 0;
  435.     new_entry->memory_ptr = 
  436.       make_word_occurrance_block(WORD_MEMORY_INIT_BLOCK_SIZE);
  437.     new_entry->current_memory_ptr = new_entry->memory_ptr;
  438.     new_entry->memory_size = WORD_MEMORY_INIT_BLOCK_SIZE;
  439.     new_entry->current_doc_id = 0;
  440.         
  441.     the_word_memory_hashtable->contents[index] = new_entry;
  442.     return(new_entry);
  443.   }
  444.   else{
  445.     return(the_word_memory_hashtable->contents[index]);
  446.   }
  447. }
  448.  
  449. static unsigned char add_weight _AP((long current_weight,long new_weight));
  450.  
  451. static unsigned char 
  452. add_weight(current_weight,new_weight)
  453. long current_weight;
  454. long new_weight;
  455. /* add a new weight to the existing one */
  456. {
  457.   /* this should be smarter than this, like doing the log or something */
  458.   if(127 < (current_weight + new_weight)){
  459.     /* the max char.  should be 255, but does not work on all compilers */
  460.     return(127);
  461.   }
  462.   else{
  463.     return(current_weight + new_weight);
  464.   }
  465. }
  466.  
  467. static char* more_memory _AP((char* current_memory_ptr,
  468.                   long current_memory_size,
  469.                   long new_size));
  470.  
  471. static char* more_memory(current_memory_ptr,current_memory_size,new_size)
  472. char* current_memory_ptr;
  473. long current_memory_size;
  474. long new_size;
  475. /* Allocates more memory for a word_entry.  It transfers all the bytes 
  476.  * from the old to the new and then returns the new.
  477.  */
  478. {
  479.   char* new_memory = NULL;
  480.   if(current_memory_size > new_size){
  481.     panic("trying to contract a word_entry block.  This is not right\n");
  482.   }
  483.   new_memory = make_word_occurrance_block(new_size);
  484.   if(NULL == new_memory){
  485.     panic("Out of memory.");
  486.   }
  487.   memset(new_memory, 0, new_size);
  488.   memmove(new_memory, current_memory_ptr, (size_t)current_memory_size); 
  489.   return(new_memory);
  490. }
  491.  
  492. static long more_memory_size _AP((long current_size,
  493.                   long number_of_occurances));
  494.  
  495. static long more_memory_size(current_size,number_of_occurances)
  496. long current_size;
  497. long number_of_occurances;
  498. /* This is pretty important to get right.  This is a place holder */
  499. {
  500.   return(MAX(2 * current_size, WORD_MEMORY_INIT_BLOCK_SIZE));
  501. }
  502.  
  503. static long write_bytes_to_memory _AP((long value,long size,char* ptr));
  504.  
  505. static long write_bytes_to_memory(value,size,ptr)
  506. long value;
  507. long size;
  508. char* ptr;
  509. {
  510.   /* writes the number into memory lsb first.  
  511.      returns the number of bytes written */
  512.   long i;
  513.   if(size < 0) /* paranoia */
  514.     panic("attempting to write a negative number of bytes");
  515.  
  516.   ptr += size; /* start at the end of the block and write backwards */
  517.   for (i = 0; i < size; i++){
  518.     ptr--;
  519.     *ptr = value & 0xFF;
  520.     value = value >> 8;
  521.   }
  522.   return(size);
  523. }
  524.             
  525. /* adds a word to the word_memory_hashtable. Currently it
  526.  * ignores the character position XXX.  
  527.  * Returns the 0 if successful. See irext.h for more documentation.
  528.  */
  529. long add_word(word, char_pos, line_pos,
  530.           weight, doc_id, date, db)
  531.      char *word;    /* the word to be indexed, this could be a
  532.                word pair. If NULL there are no more words
  533.                to be indexed */
  534.      long char_pos;    /* the position of the start of the
  535.                word */
  536.      long line_pos;    /* this is passed for the best
  537.                section calculation */
  538.      long weight;    /* how important the word looks
  539.                syntactically (such as is it bold)
  540.                NOT used by signature system */
  541.      long doc_id;     /* current document, this will never be 0 */
  542.      time_t date; /* display day of this document, 0 if not known */
  543.      database* db; /* database to insert the document */
  544. {
  545.   /* look up the word in the word_memory_hashtable */
  546.   /* creates it if necessary */    
  547.   word_entry* wrd_entry;
  548.   word_memory_hashtable * the_word_memory_hashtable = db->the_word_memory_hashtable;
  549.   /* printf("Word: '%s' doc_id: %ld, pos: %ld, weight: %ld\n",
  550.      word, doc_id, char_pos, weight); */
  551.   
  552.   if(NULL == db->the_word_memory_hashtable){
  553.     panic("The memory word hashtable is not defined.");
  554.   }
  555.  
  556.   /* if we have filled up the hashtable, or if we have indexed enough words
  557.      flush the memory copies to disk */
  558.   if((the_word_memory_hashtable->number_of_entries ==
  559.       the_word_memory_hashtable->word_entry_block_size) ||
  560.      (the_word_memory_hashtable->number_of_words_indexed ==
  561.       the_word_memory_hashtable->flush_after_n_words))
  562.     flush_memory_hashtable_to_disk(db, false);
  563.   
  564.   the_word_memory_hashtable->number_of_words_indexed ++;
  565.   wrd_entry = look_up_word(word, the_word_memory_hashtable);
  566.   wrd_entry->number_of_occurances ++;
  567.  
  568.   if(wrd_entry->number_of_occurances > MAX_OCCURANCES){
  569.     /* do nothing. we have enough of that word */
  570.   }
  571.   else{
  572.     /* we have a word to add */
  573.     if(doc_id != wrd_entry->current_doc_id){
  574.       /* then we have a new doc_id to add to the memory block */
  575.       wrd_entry->current_doc_id = doc_id;
  576.           
  577.       /* check to see if we need more memory */
  578.       if((wrd_entry->memory_size -
  579.       (wrd_entry->current_memory_ptr - 
  580.        wrd_entry->memory_ptr) 
  581.       < 
  582.       DICTIONARY_ELEMENT_SIZE)){
  583.     /* we need more memory. this makes more and frees the old*/
  584.     char* old_memory_ptr = wrd_entry->memory_ptr;
  585.  
  586.     long new_size = 
  587.       more_memory_size(wrd_entry->memory_size,
  588.                wrd_entry->number_of_occurances);
  589.     /* cprintf(PRINT_AS_INDEXING, "Get more memory %ld bytes for %s\n", new_size, word); */
  590.     wrd_entry->memory_ptr = 
  591.       more_memory(wrd_entry->memory_ptr, wrd_entry->memory_size,
  592.               new_size);
  593.     wrd_entry->current_memory_ptr = 
  594.       wrd_entry->memory_ptr + /* new offset */
  595.         (wrd_entry->current_memory_ptr - old_memory_ptr);
  596.     /* just being paranoid... no longer illegal
  597.        if(wrd_entry->current_memory_ptr == wrd_entry->memory_ptr)
  598.        panic("After allocating more memory, the size went to 0");
  599.        */
  600.     wrd_entry->memory_size = new_size;
  601.       }                /* finished making more memory */
  602.  
  603.       /* add away */
  604.       wrd_entry->current_memory_ptr +=
  605.     write_bytes_to_memory(doc_id, DOCUMENT_ID_SIZE,
  606.                   wrd_entry->current_memory_ptr);
  607.       wrd_entry->current_memory_ptr +=
  608.     write_bytes_to_memory(char_pos, 
  609.                   CHARACTER_POSITION_SIZE,
  610.                   wrd_entry->current_memory_ptr);
  611.       wrd_entry->current_memory_ptr +=
  612.     write_bytes_to_memory(weight + 5, /* add 5 since for the first one */
  613.                   WEIGHT_SIZE,
  614.                   wrd_entry->current_memory_ptr);
  615.     }
  616.     else{
  617.       /* The word is already there,
  618.        * just increment the weight in the record.
  619.        * This will change when/if position information is kept (for proximity).
  620.        */
  621.       if(wrd_entry->current_memory_ptr == wrd_entry->memory_ptr){
  622.     panic("Memory hashtable error. Recorded doc_id %ld, current doc_id %ld\n",
  623.           wrd_entry->current_doc_id, doc_id);
  624.       }
  625.       *(wrd_entry->current_memory_ptr - 1) =
  626.     add_weight(*(wrd_entry->current_memory_ptr - 1), weight);
  627.     }
  628.   }
  629.   return(0L);
  630. }
  631.  
  632. void add_stop_words(the_word_memory_hashtable)
  633. word_memory_hashtable *the_word_memory_hashtable;
  634.      /* add the stop words to the hashtable.  this must be done before
  635.     adding other words */
  636. {
  637.   init_stop_list();
  638.   while(true){
  639.     char *word = next_stop_word();
  640.     word_entry* wrd_entry;
  641.  
  642.     if(NULL == word)
  643.       break;
  644.     wrd_entry = look_up_word(word, the_word_memory_hashtable);
  645.     wrd_entry->number_of_occurances = STOP_WORD_FLAG;
  646.   }
  647. }
  648.  
  649. /* this clears the contents of the word_memory_hashtable */
  650. void clear_word_memory_hashtable(the_word_memory_hashtable)
  651. word_memory_hashtable *the_word_memory_hashtable;
  652. {
  653.   memset((char*)the_word_memory_hashtable->contents, 0,
  654.      ((long)the_word_memory_hashtable->size * 
  655.       sizeof(size_t)));
  656.   the_word_memory_hashtable->number_of_entries = 0;
  657.   the_word_memory_hashtable->number_of_words_indexed = 0;
  658. }
  659.  
  660.  
  661. /* Size is in the number of entries.  
  662.    flush_after_n_words sets the hashtable flush parameter.
  663.    Returns TRUE if it succeeds. */
  664. word_memory_hashtable * init_word_memory_hashtable(size,flush_after_n_words,the_word_memory_hashtable)
  665. long size;
  666. long flush_after_n_words;
  667. word_memory_hashtable* the_word_memory_hashtable;
  668. {
  669.   if(NULL != the_word_memory_hashtable){
  670.     /* then displose of the old one */
  671.     if(NULL != the_word_memory_hashtable->contents)
  672.       s_free(the_word_memory_hashtable->contents);
  673.     if(NULL != the_word_memory_hashtable->word_entry_block)
  674.       s_free(the_word_memory_hashtable->word_entry_block);
  675.     flush_word_occurance_buffers();
  676.   }
  677.   the_word_memory_hashtable = 
  678.     (word_memory_hashtable*)s_malloc((size_t)sizeof(word_memory_hashtable));
  679.  
  680.   the_word_memory_hashtable->size = size;
  681.   
  682.   the_word_memory_hashtable->word_entry_block_size = size / 2;
  683.     
  684.   the_word_memory_hashtable->contents = 
  685.     (word_entry **)s_malloc((size_t)(the_word_memory_hashtable->size
  686.                      * sizeof(size_t)));
  687.   the_word_memory_hashtable->word_entry_block =
  688.     (word_entry *)s_malloc((size_t)(the_word_memory_hashtable->word_entry_block_size
  689.                     * sizeof(word_entry)));
  690.  
  691.   if(NULL == the_word_memory_hashtable->contents){
  692.     panic("Could not malloc for the word hashtable\n");
  693.     return(NULL);
  694.   }
  695.   /* clear the hashtable the slow by safe way
  696.   for(i = 0; i < the_word_memory_hashtable->size; i++){
  697.     the_word_memory_hashtable->contents[i] = (word_entry*)NULL;
  698.   }
  699.   */
  700.   clear_word_memory_hashtable(the_word_memory_hashtable);
  701.  
  702.   /* add the stopwords to the index */
  703.   add_stop_words(the_word_memory_hashtable);
  704.      
  705.   the_word_memory_hashtable->flush_after_n_words = 
  706.     flush_after_n_words;
  707.  
  708.   the_word_memory_hashtable->growth_factor = 2.0;
  709.   the_word_memory_hashtable->grow_when_this_full = .5;
  710.   
  711.   return(the_word_memory_hashtable);
  712. }
  713.  
  714.